﻿using System;
using System.IO;

namespace EffiProz.Core.Lib.IO
{
    public class DataOutputStream : Stream
    {
        byte[] _tempBuffer = new byte[8];
        Stream _stream;

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _stream.Seek(offset, origin);
        }


        public override void Flush() 
        {
            _stream.Flush();
        }


        public override long Position
        {
            get
            {
                return _stream.Position;
            }

            set
            {
                _stream.Position = value;
            }
        }

        public override long Length
        {
            get
            {
                return _stream.Length;
            }
        }

        public override bool CanRead
        {
            get
            {
                return false;
            }
        }

        public override bool CanSeek
        {
            get
            {
                return _stream.CanSeek;
            }
        }

        public override bool CanWrite
        {
            get
            {
                return _stream.CanWrite;
            }
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            _stream.Write(buffer, offset, count);
        }

        public override void SetLength(long value)
        {
            _stream.SetLength(value);
        }

        public override int Read(byte[] buffer, int offset, int len)
        {
            throw new NotSupportedException();
        }

        public DataOutputStream(Stream stream)
        {
            _stream = stream;
        }

        public override void WriteByte(byte v)
        {
            _stream.WriteByte(v);
        }

        public void WriteInt(int v)
        {

            int count = 0;

            byte[] bits = BitConverter.GetBytes(v);

            _tempBuffer[count++] = bits[0];
            _tempBuffer[count++] = bits[1];
            _tempBuffer[count++] = bits[2];
            _tempBuffer[count++] = bits[3];

            _stream.Write(_tempBuffer, 0, count);
        }

        public void WriteLong(long v)
        {
            int count = 0;

            byte[] bits = BitConverter.GetBytes(v);

            _tempBuffer[count++] = bits[0];
            _tempBuffer[count++] = bits[1];
            _tempBuffer[count++] = bits[2];
            _tempBuffer[count++] = bits[3];
            _tempBuffer[count++] = bits[4];
            _tempBuffer[count++] = bits[5];
            _tempBuffer[count++] = bits[6];
            _tempBuffer[count++] = bits[7];

            _stream.Write(_tempBuffer, 0, count);
        }

        public void WriteChar(char v)
        {

            int count = 0;

            byte[] bits = BitConverter.GetBytes(v);

            _tempBuffer[count++] = bits[0];
            _tempBuffer[count++] = bits[1];

            _stream.Write(_tempBuffer, 0, count);
        }

        public void WriteChars(String s)
        {

            int len = s.Length;

            for (int i = 0; i < len; i++)
            {
                char v = s[i];
                int count = 0;

                byte[] bits = BitConverter.GetBytes(v);

                _tempBuffer[count++] = bits[0];
                _tempBuffer[count++] = bits[1];

                _stream.Write(_tempBuffer, 0, count);
            }
        }

        public void WriteChars(char[] c)
        {
            WriteChars(c, c.Length);
        }

        public void WriteChars(char[] c, int length)
        {

            for (int i = 0; i < length; i++)
            {
                char v = c[i];
                int count = 0;

                byte[] bits = BitConverter.GetBytes(v);

                _tempBuffer[count++] = bits[0];
                _tempBuffer[count++] = bits[1];

                _stream.Write(_tempBuffer, 0, count);
            }
        }

        public void Write(byte[] bytes)
        {
            _stream.Write(bytes, 0, bytes.Length);
        }

        public void Write(TextReader reader, long length)
        {

            char[] buffer = new char[1024];
            int index = 0, count = 1024;

            do
            {
                count = reader.Read(buffer, index, buffer.Length);
                WriteChars(buffer);
                index += count;
            } while (count > 0);

        }

        public void Write(Stream inputStream,
                          long length)
        {

            CountdownInputStream countStream =
                new CountdownInputStream(inputStream);

            countStream.setCount(length);

            byte[] data = new byte[128];
            int offset = 0;

            while (true)
            {
                int count = countStream.Read(data, offset, data.Length);
                offset += count;
                if (count < 1)
                {
                    if (countStream.getCount() != 0)
                    {
                        throw new EndOfStreamException();
                    }

                    break;
                }

                _stream.Write(data, 0, count);
            }
        }
    }
}
